/**
 * 
 */
package com.psytech.app.task.driver.user.impl.xml;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.security.auth.login.CredentialException;
import javax.xml.namespace.QName;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;

import taskmanager.psytech.com.taskmanagerservice._1.BusinessFaultMsg;
import taskmanager.psytech.com.taskmanagerservice._1.ObjectFactory;
import taskmanager.psytech.com.taskmanagerservice._1.TaskManagerService_Service;
import taskmanager.psytech.com.taskmanagerservice._1.TechnicalFaultMsg;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.psytech.app.task.web_ui.Group;
import com.psytech.app.task.web_ui.User;
import com.psytech.app.task.web_ui.driver.UserDriverInterface;
import com.psytech.app.task.web_ui.driver.exception.ObjectNotFoundException;

/**
 * 
 */
public class XmlUserDriver implements UserDriverInterface {

	private static Logger LOG = Logger.getLogger(XmlUserDriver.class.getPackage().getName());

	private XMLConfiguration conf;

	taskmanager.psytech.com.taskmanagerservice._1.TaskManagerService managerService;

	private final static ObjectFactory OBJECT_FACTORY = new ObjectFactory();

	private final Map<String, User> ips = new HashMap<String, User>();

	private final Map<String, User> uidToUiUser = new HashMap<String, User>();

	private final Multimap<String, User> guidToMembers = HashMultimap.create();

	private final Multimap<String, Group> usersGroupsAssigment = HashMultimap.create();

	@Override
	public void setServiceUri(final String serviceUri) {
		LOG.log(Level.FINE, "XmlUserDriver config file : " + serviceUri);
		try {
			this.conf = new XMLConfiguration(serviceUri);
		} catch (final ConfigurationException e) {
			throw new RuntimeException("Fichier de configuration non trouvé", e);

		}

		final String wsdlLocation = this.conf.getString("taskService[@wsdlUrl]");
		if (wsdlLocation == null)
			throw new RuntimeException("Please verify your config file");
		try {
			LOG.info("wsdlLocation " + wsdlLocation);
			final TaskManagerService_Service managerServiceService = new TaskManagerService_Service(new URL(
					wsdlLocation), new QName("http://com.psytech.taskmanager/TaskManagerService/1",
					"TaskManagerService"));
			this.managerService = managerServiceService.getTaskManagerServiceSOAP();
		} catch (final MalformedURLException e) {
			throw new IllegalStateException("Probléme lors de l'initialisation du service", e);
		}

		final Map<String, User> LoginToUiUser = new HashMap<String, User>();
		final List<HierarchicalConfiguration> user = this.conf.configurationsAt("users.user");
		for (final HierarchicalConfiguration sub : user) {
			final String name = sub.getString("name");
			LOG.log(Level.FINER, name);
			final taskmanager.psytech.com.taskmanagerservice._1.User userToFind = OBJECT_FACTORY.createUser();
			userToFind.setLogin(name);
			try {
				final List<taskmanager.psytech.com.taskmanagerservice._1.User> users = this.managerService.getUsers(
						userToFind).getUser();
				if (users.size() > 0) {
					final User uiUser = this.taskUserToUIUser(users.get(0));
					uiUser.setEmail(sub.getString("mail"));
					this.ips.put(sub.getString("host"), uiUser);
					this.uidToUiUser.put(uiUser.getUid(), uiUser);
					LoginToUiUser.put(uiUser.getLogin(), uiUser);
				}
			} catch (final BusinessFaultMsg exception) {
				LOG.log(Level.WARNING, exception.getFaultInfo().getMessage());
				throw new IllegalArgumentException(exception.getFaultInfo().getMessage());
			} catch (final TechnicalFaultMsg exception) {
				LOG.log(Level.WARNING, exception.getFaultInfo().getMessage());
				throw new IllegalStateException(exception.getFaultInfo().getMessage());
			} catch (final Exception e) {
				LOG.log(Level.WARNING, "Error on user search", e);
				throw new RuntimeException();
			}
		}

		final List<HierarchicalConfiguration> groups = this.conf.configurationsAt("groups.group");
		for (final HierarchicalConfiguration group : groups) {
			final Group uiGroup = new Group();
			uiGroup.setGuid(group.getString("guid"));
			uiGroup.setName(group.getString("name"));
			LOG.log(Level.FINER, group.getString("name"));
			final List<String> members = group.getList("members.member");
			for (final String member : members)
				if (LoginToUiUser.containsKey(member)) {
					this.usersGroupsAssigment.put(LoginToUiUser.get(member).getUid(), uiGroup);
					this.guidToMembers.put(uiGroup.getGuid(), LoginToUiUser.get(member));
					LOG.log(Level.FINER, member);
				}
		}

	}

	@Override
	public void setUserName(final String userName) {
		throw new UnsupportedOperationException();

	}

	@Override
	public void setPassword(final String password) {
		throw new UnsupportedOperationException();
	}

	/* (non-Javadoc)
	 * @see com.psytech.app.task.web_ui.driver.UserDriverInterface#getUserGroups(java.lang.String)
	 */
	@Override
	public List<Group> getUserGroups(final String userUid) throws ObjectNotFoundException {
		return new ArrayList<Group>(this.usersGroupsAssigment.get(userUid));
	}

	/* (non-Javadoc)
	 * @see com.psytech.app.task.web_ui.driver.UserDriverInterface#getGroupMembers(java.lang.String)
	 */
	@Override
	public List<User> getGroupMembers(final String groupUid) throws ObjectNotFoundException {
		return new ArrayList<User>(this.guidToMembers.get(groupUid));
	}

	/* (non-Javadoc)
	 * @see com.psytech.app.task.web_ui.driver.UserDriverInterface#getUserByUid(java.lang.String)
	 */
	@Override
	public User getUserByUid(final String uid) throws ObjectNotFoundException {
		return this.uidToUiUser.get(uid);

	}

	/* (non-Javadoc)
	 * @see com.psytech.app.task.web_ui.driver.UserDriverInterface#getUserByCredential(java.lang.String, java.lang.String)
	 */
	@Override
	public User getUserByCredential(final String login, final String password) throws CredentialException {
		throw new UnsupportedOperationException();
	}

	/* (non-Javadoc)
	 * @see com.psytech.app.task.web_ui.driver.UserDriverInterface#getUserByAuthenticationToken(java.lang.String)
	 */
	@Override
	public User getUserByAuthenticationToken(final String token) throws CredentialException {
		throw new UnsupportedOperationException();
	}

	private User taskUserToUIUser(final taskmanager.psytech.com.taskmanagerservice._1.User user) {
		final User uiUser = new User();
		uiUser.setLogin(user.getLogin());
		LOG.log(Level.FINER, "taskUserTOUIUser user uid :" + user.getUid());
		uiUser.setUid(user.getUid());
		return uiUser;
	}

	public User getUserByIp(final String ip) {
		return this.ips.get(ip);
	}
}
